<template>
  <el-upload
    multiple
    :headers="headers"
    :action="uploadUrl"
    :before-remove="beforeRemove"
    :on-exceed="handleExceed"
    :on-success="handleSuccess"
    :on-remove="handleRemove"
    :on-preview="handlePreview"
    :file-list="fileList"
    v-bind="fileProps"
    class="avatar-uploader"
  >
    <template v-if="uploadType === 'img'">
      <i v-if="fileList.length < max" slot="trigger" class="el-icon-plus avatar-uploader-icon"></i>
      <div
        v-for="(item, index) in fileList"
        :key="index"
        class="img-item"
        @click.stop="handlePreview(item)"
      >
        <img class="avatar" :src="item.response" alt="" />
        <span class="item-actions">
          <span class="item-delete" @click.stop="onDelete(index)">
            <i class="el-icon-delete"></i>
          </span>
        </span>
      </div>
    </template>
    <div slot="tip" class="el-upload__tip">{{ tips }}</div>
    <el-button
      v-if="uploadType === 'file'"
      :disabled="disabled"
      size="small"
      type="primary"
      v-bind="buttonProp"
    >
      {{ buttonText }}
    </el-button>
  </el-upload>
</template>

<script>
import { mapState } from 'vuex'

import { getDomainByEnv } from '@/utils'
import * as api from '@/const/api'

export default {
  props: {
    // v-model 绑定的值
    value: {
      type: [Array, String],
      default: '',
    },
    uploadType: {
      type: String,
      default: 'img',
    },
    // 最大可上传数量
    max: {
      type: Number,
      default: 9,
    },
    // 上传文件类型，默认word，excel
    accept: {
      type: String,
      default: '.doc,.docx,.xlsx,.xls',
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false,
    },
    // 文本提示
    tips: {
      type: String,
      default: '',
    },
    // 是否显示预览文件列表
    showFileList: {
      type: Boolean,
      default: false,
    },
    // 覆盖默认的上传行为，可以自定义上传的实现
    httpRequest: {
      type: Function,
      default: null,
    },
    buttonText: {
      type: String,
      default: '上传',
    },
    // 按钮自定义属性
    buttonProp: {
      type: Object,
      default: () => {
        return {}
      },
    },
    /**
     * @onSuccess
     * 上传成功回调
     */
    onSuccess: {
      type: Function,
      default: null,
    },
  },
  data() {
    return {
      uploadUrl: `${getDomainByEnv()}${api.upload}`,
    }
  },
  computed: {
    ...mapState(['token']),
    headers() {
      return {
        Authorization: this.token,
      }
    },
    fileList: {
      get() {
        if (!this.value) {
          return []
        }
        return this.value
      },
      set(val) {
        // 触发v-model绑定值更新
        this.$emit('input', val)
      },
    },
    fileProps() {
      const props = {
        limit: this.max,
        accept: this.accept,
        disabled: this.disabled,
        showFileList: this.showFileList,
      }

      if (this.httpRequest) {
        props.httpRequest = this.httpRequest
      }
      return props
    },
  },
  methods: {
    onDelete(index) {
      this.fileList.splice(index, 1)
      this.$emit('onSuccess', [...this.fileList]) // 上传成功回调
    },
    handleRemove(file, fileList) {
      this.fileList = fileList
      this.$emit('onSuccess', fileList) // 上传成功回调
    },
    // 超过限制提示
    handleExceed(files, fileList) {
      this.$message.warning(
        `当前限制选择 ${this.max} 个文件，本次选择了 ${files.length} 个文件，共选择了 ${
          files.length + fileList.length
        } 个文件`
      )
    },
    handleSuccess(response, file, fileList) {
      // 处理下response数据，不然层级太深
      this.fileList = fileList.map((item) => ({
        ...item,
        response: item.response.data || item.response,
      }))
      this.$emit('onSuccess', fileList) // 上传成功回调
    },
    // 预览
    handlePreview(file) {
      window.open(decodeURIComponent(file.response), '_blank')
    },
    beforeRemove(file, fileList) {
      return this.$confirm(`确定移除 ${file.name}？`)
    },
  },
}
</script>

<style lang="less" scoped>
.avatar-uploader {
  font-size: 0;

  .avatar {
    width: 120px;
    height: 120px;
    display: block;
  }

  .avatar-uploader-icon {
    border: 1px dashed #d9d9d9;
    font-size: 28px;
    color: #8c939d;
    width: 120px;
    height: 120px;
    line-height: 120px;
    text-align: center;
  }

  .img-item {
    display: inline-block;
    margin-bottom: 10px;
    vertical-align: top;
    position: relative;

    &:nth-child(2n) {
      margin-left: 10px;
    }

    &:hover {
      .item-actions {
        display: flex;
      }
    }
  }

  .item-actions {
    background-color: rgba(0, 0, 0, 0.3);
    display: none;
    height: 100%;
    position: absolute;
    width: 100%;
    top: 0;
    font-size: 20px;
    color: #fff;
    align-items: center;
    justify-content: center;
  }
}
</style>
